package glog2

import (
	"context"
	"fmt"
	"github.com/Shopify/sarama"
	"github.com/sirupsen/logrus"
	"strings"
)

type Core struct {
	AppName     string
	TracePrefix string
	kafka       *moduleKafka
	ctx         context.Context
}

func (c *Core) newTextFormatter() *textFormatter {
	return &textFormatter{core: c}
}

type textFormatter struct {
	core *Core
}

func (t *textFormatter) Format(e *logrus.Entry) (o []byte, err error) {
	format := "%s <%s>"
	args := []interface{}{e.Time.Format("2006/01/02 15:04:05"), e.Level}

	prefix := t.core.TracePrefix
	if len(prefix) > 0 {
		format += " [%s]"
		args = append(args, prefix)
	}
	format += " %s\n"
	args = append(args, e.Message)

	str := fmt.Sprintf(format, args...)
	o = []byte(str)
	return
}
func New(appName string) *Core {
	c := &Core{
		AppName: appName,
		ctx:     context.Background(),
	}
	logrus.SetFormatter(c.newTextFormatter())

	return c
}

func (c *Core) SetZK(hosts ...string) {
	if c.kafka != nil {
		c.kafka.close()
	}
	h := &hook{
		c,
		make(chan *logrus.Entry, 1000),
	}
	sarama.PanicHandler = func(i interface{}) {
		logrus.Errorf("%s sarama panic: %s", pkgTag, i)
	}
	logrus.AddHook(h)

	c.kafka = newModuleKafka(hosts, h.logCh, c.ctx)
	c.kafka.start()
}

func (c *Core) connectKafka() {

}

type hook struct {
	core  *Core
	logCh chan *logrus.Entry
}

func logNotToKafka() *logrus.Entry {
	return logrus.WithField("notToKafka", true)
}

func (h *hook) Fire(entry *logrus.Entry) error {
	if toKafka, ok := entry.Data["notToKafka"]; ok {
		if value, ok2 := toKafka.(bool); ok2 {
			if value {
				return nil
			}
		}
	}

	entryNew := entry.WithField("app", h.core.AppName)
	trace := h.core.TracePrefix
	if trace_, ok := entry.Data["trace"]; ok {
		if trace_, ok := trace_.(string); ok {
			trace = strings.Join([]string{
				trace, trace_,
			}, "/")
		}
	}
	entryNew.Data["trace"] = trace
	entryNew.Level = entry.Level
	entryNew.Message = entry.Message
	entryNew.Time = entry.Time

	select {
	case h.logCh <- entryNew:
	case <-h.logCh:
		logNotToKafka().Warningf("缓存已满")
	}

	return nil
}
func (h hook) Levels() []logrus.Level {
	levels := []logrus.Level{
		logrus.DebugLevel,
		logrus.InfoLevel,
		logrus.WarnLevel,
		logrus.PanicLevel,
		logrus.ErrorLevel,
		logrus.FatalLevel,
	}
	return levels
}
